﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace Jay.Sc2.Bof.Lib.Entity
{
	public class EntityXmlLoader
	{
		public static EntityXmlLoader Instance = new EntityXmlLoader();

		private Dictionary<int, IEntity> m_Entities = new Dictionary<int,IEntity>();
		private Dictionary<string, IEntity> m_EntitiesByName = new Dictionary<string, IEntity>();

		public IEntity Get(int id) { return m_Entities[id]; }
		public IEntity Get(string name) { return m_EntitiesByName[name]; }

		public List<IEntity> CreateEntityList(string filename, string race)
		{
			XmlDocument document = new XmlDocument();
			document.Load(filename);
			return CreateEntityList(document, race);
		}
		public List<IEntity> CreateEntityList(XmlDocument document, string race)
		{
			XmlNode node = document.SelectSingleNode("/Races/Race[@Name=\"" + race + "\"]");
			if (node == null) return null;
			return CreateEntityList(node);
		}
		public List<IEntity> CreateEntityList(XmlNode node)
		{
			List<IEntity> list = new List<IEntity>();
			foreach (XmlNode child in node)
				list.Add(CreateEntity(child));
			foreach (XmlNode child in node)
			{
				XmlAttribute id = child.Attributes["ID"];
				IEntity entity = m_Entities[int.Parse(id.Value)];
				LoadProducers(child, entity);
				LoadRequirements(child, entity);
				LoadInputs(child, entity);
			}
			return list;
		}
		public IEntity CreateEntity(XmlNode node)
		{
			switch (node.Name)
			{
				case "Unit": return CreateUnit(node);
				case "Building": return CreateBuilding(node);
				case "Upgrade": return CreateUpgrade(node);
				case "Special": return CreateSpecial(node);
				default: throw new Exception("Unknow entity Type : '" + node.Name + "'.");
			}
		}
		private IEntity CreateSpecial(XmlNode node)
		{
			Special special = new Special();
			LoadEntity(node, special);
			return special;
		}
		private IEntity CreateUpgrade(XmlNode node)
		{
			Upgrade upgrade = new Upgrade();
			LoadEntity(node, upgrade);
			return upgrade;
		}
		private IEntity CreateBuilding(XmlNode node)
		{
			Building building = new Building();
			LoadEntity(node, building);
			return building;
		}
		private IUnit CreateUnit(XmlNode node)
		{
			Unit unit = new Unit();
			LoadEntity(node, unit);
			XmlAttribute food = node.Attributes["Food"];
			if (food != null) unit.Food = int.Parse(food.Value);
			return unit;
		}
		private void LoadEntity(XmlNode node, Entity entity)
		{
			XmlAttribute id = node.Attributes["ID"];
			XmlAttribute name = node.Attributes["Name"];
			XmlAttribute time = node.Attributes["Time"];
			XmlAttribute minerals = node.Attributes["Minerals"];
			XmlAttribute gas = node.Attributes["Gas"];
			XmlAttribute supply = node.Attributes["Supply"];
			entity.ID = int.Parse(id.Value);
			entity.Name = name.Value;
			entity.Time = int.Parse(time.Value);
			if(minerals != null) entity.Minerals = int.Parse(minerals.Value);
			if (gas != null) entity.Gas = int.Parse(gas.Value);
			if (supply != null) entity.Supply = int.Parse(supply.Value);
			m_Entities.Add(entity.ID, entity);
			m_EntitiesByName.Add(entity.Name, entity);
		}
		private void LoadProducers(XmlNode node, IEntity entity)
		{
			XmlNode producers = node.SelectSingleNode("Producers");
			if (producers == null) return;
			foreach (XmlNode child in producers)
			{
				XmlAttribute id = child.Attributes["ID"];
				entity.Producers.Add(m_Entities[int.Parse(id.Value)]);
			}
		}
		private void LoadRequirements(XmlNode node, IEntity entity)
		{
			if (entity.Gas > 0) entity.Requirements.Add(m_EntitiesByName["Refinery"]);
			XmlNode requirements = node.SelectSingleNode("Requirements");
			if (requirements == null) return;
			foreach (XmlNode child in requirements)
			{
				XmlAttribute id = child.Attributes["ID"];
				entity.Requirements.Add(m_Entities[int.Parse(id.Value)]);
			}
		}
		private void LoadInputs(XmlNode node, IEntity entity)
		{
			XmlNode requirements = node.SelectSingleNode("Inputs");
			if (requirements == null) return;
			foreach (XmlNode child in requirements)
			{
				Dictionary<IEntity, int> input = new Dictionary<IEntity,int>();
				foreach (XmlNode subChild in child)
				{
					XmlAttribute id = subChild.Attributes["ID"];
					IEntity key = m_Entities[int.Parse(id.Value)];
					int count = 0;
					if (input.TryGetValue(key, out count))
					{
						count++;
						input[key] = count;
					}
					else
						input.Add(key, 1);
				}
				if (input.Count > 0)
					entity.Inputs.Add(input);
			}
		}
	}
}
